#include <buola/gui/cwindow.h>
#include <buola/image/cgc.h>
#include <buola/app/ceventloop.h>

using namespace buola;

class CTestWindow : public gui::CWindow
{
public:
    CTestWindow()
    {
        SetBackColor(img::CColor(1,1,1,1));
        SetTitle(L"main window");
    }
    
    void OnExpose(const gui::CExposeEvent &pE)
    {
        start_timer();
        img::CGC *lGC=pE.mGC;
#if 0
        lGC->SetLineWidth(1.5);
        //lGC.SetLineCap(img::ELineCap::SQUARE);
        lGC->SetLineJoin(img::ELineJoin::MITER);
        img::CLinearGradient lGradient({0,0},{200,200});
        lGradient.AddStop(img::CColor(1,0,0),0.0);
        lGradient.AddStop(img::CColor(0,1,0),0.2);
        lGradient.AddStop(img::CColor(0,0,1),1.0);
//        for(int i=0;i<5000;i++)
        {
            lGC->Path().MoveTo({50,50});
            lGC->Path().LineTo({200,50});
            lGC->Path().LineTo({80,170});
            lGC->Path().LineTo({125,10});
            lGC->Path().LineTo({170,170});
            lGC->Path().LineTo({50,50});
            lGC->SetSource(lGradient);
            lGC->FillPath(true);
            lGC->SetSource(img::CColor(L"DeepPink"));
            lGC->StrokePath();
        }
#endif

//arc
#if 0
        CPoint_d lCenter(128,128);
        double lRadius=100.0;
        double lAngle1=deg2rad(45.0);
        double lAngle2=deg2rad(180.0);

        lGC->SetLineWidth(10.0);
        lGC->Path().Arc(lCenter,lRadius,lAngle1,lAngle2);
        lGC->StrokePath();
        
        lGC->SetSource(img::CColor(1,0.2,0.2,0.6));
        lGC->SetLineWidth(6.0);

        lGC->Path().Arc(lCenter,10.0,0,2*M_PI);
        lGC->FillPath();

        lGC->Path().Arc(lCenter,lRadius,lAngle1,lAngle1);
        lGC->Path().LineTo(lCenter);
        lGC->Path().Arc(lCenter,lRadius,lAngle2,lAngle2);
        lGC->Path().LineTo(lCenter);
        lGC->StrokePath();
#endif
//arc negative
for(int i=0;i<1000;i++)
{
#if 1
        CPoint_d lCenter(128,128);
        double lRadius=100.0;
        double lAngle1=deg2rad(45.0);
        double lAngle2=deg2rad(-180.0);

        lGC->SetLineWidth(10.0);
        lGC->Path().Arc(lCenter,lRadius,lAngle1,lAngle2);
        lGC->StrokePath();

        lGC->SetSource(img::CColor(1,0.2,0.2,0.6));
        lGC->SetLineWidth(6.0);

        lGC->Path().Arc(lCenter,10.0,0,2*M_PI);
        lGC->FillPath();

        lGC->Path().Arc(lCenter,lRadius,lAngle1,lAngle1);
        lGC->Path().LineTo(lCenter);
        lGC->Path().Arc(lCenter,lRadius,lAngle2,lAngle2);
        lGC->Path().LineTo(lCenter);
        lGC->StrokePath();
#endif
}
//clip
#if 0
        lGC->Path().Arc({128,128},76.8);
        lGC->ClipPath();
        
        lGC->Path().Rect({0,0,256,256});
        lGC->FillPath();
        
        lGC->SetSource(img::CColor(0,1,0));
        lGC->Path().MoveTo(0,0);
        lGC->Path().LineTo(256,256);
        lGC->Path().MoveTo(256,0);
        lGC->Path().LineTo(0,256);
        lGC->SetLineWidth(10.0);
        lGC->StrokePath();
#endif
//clip image
//curve rectangle
#if 0
///\todo fix the stroke for curves!!!
        CRect_d lRect(25.6,25.6,230.4,230.4);
        double lRadius=102.4;
        CPoint_d lCenter=lRect.Center();

        if(lRect.w()/2<lRadius)
        {
            if(lRect.h()/2<lRadius)
            {
                lGC->Path().MoveTo({lRect.l,lCenter.y});
                lGC->Path().CurveTo({lRect.l,lRect.t},{lRect.l,lRect.t},{lCenter.x,lRect.t});
                lGC->Path().CurveTo({lRect.r,lRect.t},{lRect.r,lRect.t},{lRect.r,lCenter.y});
                lGC->Path().CurveTo({lRect.r,lRect.b},{lRect.r,lRect.b},{lCenter.x,lRect.b});
                lGC->Path().CurveTo({lRect.l,lRect.b},{lRect.l,lRect.b},{lRect.l,lCenter.y});
            }
            else
            {
                lGC->Path().MoveTo({lRect.l,lRect.t+lRadius});
                lGC->Path().CurveTo({lRect.l,lRect.t},{lRect.l,lRect.t},{lCenter.x,lRect.t});
                lGC->Path().CurveTo({lRect.r,lRect.t},{lRect.r,lRect.t},{lRect.r,lRect.t+lRadius});
                lGC->Path().LineTo({lRect.r,lRect.b-lRadius});
                lGC->Path().CurveTo({lRect.r,lRect.b},{lRect.r,lRect.b},{lCenter.x,lRect.b});
                lGC->Path().CurveTo({lRect.l,lRect.b},{lRect.l,lRect.b},{lRect.l,lRect.b-lRadius});
            }
        }
        else
        {
            if(lRect.h()/2<lRadius)
            {
                lGC->Path().MoveTo({lRect.l,lCenter.y});
                lGC->Path().CurveTo({lRect.l,lRect.t},{lRect.l,lRect.t},{lRect.l+lRadius,lRect.t});
                lGC->Path().LineTo({lRect.r-lRadius,lRect.t});
                lGC->Path().CurveTo({lRect.r,lRect.t},{lRect.r,lRect.t},{lRect.r,lCenter.y});
                lGC->Path().CurveTo({lRect.r,lRect.b},{lRect.r,lRect.b},{lRect.r-lRadius,lRect.b});
                lGC->Path().LineTo({lRect.l+lRadius,lRect.b});
                lGC->Path().CurveTo({lRect.l,lRect.b},{lRect.l,lRect.b},{lRect.l,lCenter.y});
            }
            else
            {
                lGC->Path().MoveTo({lRect.l,lRect.t+lRadius});
                lGC->Path().CurveTo({lRect.l,lRect.t},{lRect.l,lRect.t},{lRect.l+lRadius,lRect.t});
                lGC->Path().LineTo({lRect.r-lRadius,lRect.t});
                lGC->Path().CurveTo({lRect.r,lRect.t},{lRect.r,lRect.t},{lRect.r,lRect.t+lRadius});
                lGC->Path().LineTo({lRect.r,lRect.b-lRadius});
                lGC->Path().CurveTo({lRect.r,lRect.b},{lRect.r,lRect.b},{lRect.r-lRadius,lRect.b});
                lGC->Path().LineTo({lRect.l+lRadius,lRect.b});
                lGC->Path().CurveTo({lRect.l,lRect.b},{lRect.l,lRect.b},{lRect.l,lRect.b-lRadius});
            }
        }

        lGC->Path().Close();

        lGC->SetSource(img::CColor(0.5,0.5,1));
        lGC->FillPath(true);
        lGC->SetSource(img::CColor(0.5,0,0,0.5));
        lGC->SetLineWidth(10.0);
        lGC->StrokePath();
#endif
//curve to
#if 0
        CPoint_d l1(25.6,128.0),l2(102.4,230.4),l3(153.6,25.6),l4(230.4,128.0);

        lGC->Path().MoveTo(l1);
        lGC->Path().CurveTo(l2,l3,l4);

        lGC->SetLineWidth(10.0);
        lGC->StrokePath();

        lGC->SetSource(img::CColor(1,0.2,0.2,0.6));
        lGC->SetLineWidth(6.0);
        lGC->Path().MoveTo(l1);
        lGC->Path().LineTo(l2);
        lGC->Path().MoveTo(l3);
        lGC->Path().LineTo(l4);
        lGC->StrokePath();
#endif
//dash
//fill and stroke 2
#if 0
///\todo fix line join
        lGC->Path().MoveTo(128.0,25.6);
        lGC->Path().LineTo(230.4,230.4);
        lGC->Path().RelLineTo(-102.4,0.0);
        lGC->Path().CurveTo(51.2,230.4,51.2,128.0,128.0,128.0);
        lGC->Path().Close();

        lGC->Path().MoveTo(64.0,25.6);
        lGC->Path().RelLineTo(51.2,51.2);
        lGC->Path().RelLineTo(-51.2,51.2);
        lGC->Path().RelLineTo(-51.2,-51.2);
        lGC->Path().Close();

        lGC->SetLineWidth(10.0);
        lGC->SetSource(img::CColor(0,0,1));
        lGC->FillPath(true);
        lGC->SetSource(img::CColor(0,0,0));
        lGC->StrokePath();
#endif
//fill style
//gradient
#if 0
        img::CLinearGradient lLinear({0,0},{0,256});
        lLinear.AddStop(img::CColor(1,1,1),0);
        lLinear.AddStop(img::CColor(0,0,0),1);
        lGC->Path().Rect({0,0,256,256});
        lGC->SetSource(lLinear);
        lGC->FillPath();
        img::CRadialGradient lRadial({115.2,102.4},25.6,{102.4,102.4},128);
        lRadial.AddStop(img::CColor(1,1,1),0);
        lRadial.AddStop(img::CColor(0,0,0),1);
        lGC->Path().Arc({128,128},76.8);
        lGC->SetSource(lRadial);
        lGC->FillPath();
#endif
//image
//imagepattern
//multi segment caps
#if 0
        lGC->Path().MoveTo(50.0,75.0);
        lGC->Path().LineTo(200.0,75.0);

        lGC->Path().MoveTo(200.0,125.0);
        lGC->Path().LineTo(50.0,125.0);

        lGC->Path().MoveTo(50.0,175.0);
        lGC->Path().LineTo(200.0,175.0);

        lGC->SetLineWidth(30.0);
        lGC->SetLineCap(img::ELineCap::ROUND);
        lGC->StrokePath();
#endif

//rounded rectangle
//set line cap
#if 0
        lGC->SetLineWidth(30.0);
        lGC->SetLineCap(img::ELineCap::BUTT);
        lGC->Path().MoveTo(64,50);
        lGC->Path().LineTo(64,200);
        lGC->StrokePath();
        lGC->SetLineCap(img::ELineCap::ROUND);
        lGC->Path().MoveTo(128,50);
        lGC->Path().LineTo(128,200);
        lGC->StrokePath();
        lGC->SetLineCap(img::ELineCap::SQUARE);
        lGC->Path().MoveTo(192,50);
        lGC->Path().LineTo(192,200);
        lGC->StrokePath();

        lGC->SetSource(img::CColor(1,0.2,0.2));
        lGC->SetLineWidth(2.56);
        lGC->Path().MoveTo(64,50);
        lGC->Path().LineTo(64,200);
        lGC->Path().MoveTo(128,50);
        lGC->Path().LineTo(128,200);
        lGC->Path().MoveTo(192,50);
        lGC->Path().LineTo(192,200);
        lGC->StrokePath();
#endif
//set line join
//text
#if 0
/*        
        cairo_select_font_face (cr, "Sans", CAIRO_FONT_SLANT_NORMAL,
                                    CAIRO_FONT_WEIGHT_BOLD);
        cairo_set_font_size (cr, 90.0);
*/
        img::CFontInfo lFontInfo("dejavusans",9);
        lGC->SetFont(img::CFont::Get(lFontInfo));
        lGC->DrawText({10,135},L"share",img::ETextPos::BASELINE);

/*
        cairo_move_to (cr, 70.0, 165.0);
        cairo_text_path (cr, "void");
        cairo_set_source_rgb (cr, 0.5, 0.5, 1);
        cairo_fill_preserve (cr);
        cairo_set_source_rgb (cr, 0, 0, 0);
        cairo_set_line_width (cr, 2.56);
        cairo_stroke (cr);
*/

        lGC->SetSource(img::CColor(1,0.2,0.2,0.6));
        lGC->Path().Arc({10,135},5.12);
        lGC->Path().Close();
        lGC->Path().Arc({70,165},5.12);
        lGC->FillPath();
#endif
        end_timer();
    }
};

typedef intrusive_ptr<CTestWindow> PTestWindow;

int main(int pNArg,char **pArgs)
{
    buola_init(pNArg,pArgs);

    try
    {
        PTestWindow lWindow=new CTestWindow;
        lWindow->Map();

        get_main_event_loop().Loop();
    }
    catch(std::exception &pE)
    {
        msg_info() << "caught exception " << pE.what() << "\n";
    }

    return buola_finish();
}
